package com.demo.swingquickticket.service;

import com.alibaba.fastjson.JSONObject;
import com.demo.swingquickticket.entity.*;
import com.demo.swingquickticket.util.RegUtil;
import com.demo.swingquickticket.util.http.HttpClientUtils;
import com.demo.swingquickticket.util.http.HttpContents;
import com.demo.swingquickticket.util.http.RequestEntity;
import com.demo.swingquickticket.util.http.ResponseEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class GrabTicketService {

    @Autowired
    TicketPanelService ticketPanelService;

    @Async
    public void work() {
        try {
            System.out.println("开始循环任务队列");
            while (true) {
                Order order = DataService.takeWorkQueue();
                if (order.getWorkStatus() == Order.START) {
                    analysisTicket(order);
                }
            }
        } catch (Exception e) {
            System.out.println("循环任务队列结束");
        }
    }

    //分析余票
    @Async
    public void analysisTicket(Order order) {
        List<TicketData> ticketData = ticketPanelService.searchTickets(order.getDate(), order.getFrom(), order.getTo(), order.getStationTrainCode());
        if (ticketData != null && !ticketData.isEmpty()) {
            Map<String, TicketData> ticketMap = ticketData.stream().collect(Collectors.toMap((x) -> x.getTicketDetail().getStationTrainCode(), x -> x, (x, y) -> x));
            List<String> stationTrainCode = order.getStationTrainCode();
            for (String code : stationTrainCode) {
                TicketData ticket = ticketMap.get(code);
                if (ticket != null && "Y".equals(ticket.getTicketDetail().getCanWebBuy())) {
                    String seatType = checkSeatType(order.getSeatType(), ticket.getTicketDetail());
                    if (seatType != null) {
                        //开始抢票
                        boolean grabTicketResult = grabTicket(ticket, order.getFrom(), order.getTo(), order.getUser(), seatType);
                        if (grabTicketResult) {
                            System.out.println("抢票成功");
                            DataService.removeWork(order.getMark());
                        }
                    }
                } else {
                    log.info("该票暂时无法购买");
                }
            }
        }
        if (order.getWorkStatus() == Order.START && DataService.existWork(order.getMark())) {
            try {
                log.info("抢票失败1秒后重试");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            DataService.putWorkQueue(order);
        }
    }

    //由于抢票时需要和登入用户的cookie绑定，所以只能加锁进行
    private synchronized boolean grabTicket(TicketData ticketData, String from, String to, User user, String seatType) {
        //0. 校验用户是否登入
        //1. 检测订单是否可以提交
        log.info("开始检测车次状态");
        boolean submit = submitOrderRequest(ticketData);
        //2. 下单购买
        if (submit) {
            log.info("车次检测通过");
            return initDc(ticketData, user, seatType);
        }
        return false;
    }

    //1. 校验订单是否可以提交
    private boolean submitOrderRequest(TicketData ticketData) {
        RequestEntity requestEntity = new RequestEntity("https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest", HttpContents.POST_TYPE);
        requestEntity.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        requestEntity.addHeader("Host", "kyfw.12306.cn");
        requestEntity.addHeader("Origin", "https://kyfw.12306.cn");
        requestEntity.setParamBody(buildStringBody(ticketData));
        requestEntity.setCookieList(DataService.getAccount().getLoginCookie());
        requestEntity.buildHttpClient();
        ResponseEntity responseEntity = HttpClientUtils.doRequest(requestEntity);
        System.out.println(responseEntity);
        try {
            JSONObject submitOrderRequest = JSONObject.parseObject(responseEntity.getResult());
            if (submitOrderRequest.getBoolean("status")) {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }

    //2. 开始购票
    private boolean initDc(TicketData ticketData, User user, String seatType) {
        try {
            log.info("开始初始化订票页面");
            RequestEntity requestEntity = new RequestEntity("https://kyfw.12306.cn/otn/confirmPassenger/initDc", HttpContents.POST_TYPE);
            requestEntity.setCookieList(DataService.getAccount().getLoginCookie());
            requestEntity.buildHttpClient();
            ResponseEntity responseEntity = HttpClientUtils.doRequest(requestEntity);
            String reg = "globalRepeatSubmitToken = '(.*?)'";
            String globalRepeatSubmitToken = RegUtil.regString(responseEntity.getResult(), reg);
            globalRepeatSubmitToken = globalRepeatSubmitToken.replace("globalRepeatSubmitToken = '", "");
            globalRepeatSubmitToken = globalRepeatSubmitToken.replace("'", "");
            reg = "'key_check_isChange':'(.*?)'";
            String key_check_isChange = RegUtil.regString(responseEntity.getResult(), reg);
            key_check_isChange = key_check_isChange.replace("'key_check_isChange':'", "");
            key_check_isChange = key_check_isChange.replace("'", "");
            log.info("页面初始化成功,globalRepeatSubmitToken:{},key_check_isChange:{}", globalRepeatSubmitToken, key_check_isChange);
            //var globalRepeatSubmitToken = 'af32dfa5441ca482257f60c6a3028fe1'
            //'key_check_isChange':'34188AECCF4FAB4F96EFD81008B04F6DA8886C5A5EBE946B9ECA3FDC'
            //ticketType 1. 成人票(1)
            //seatType   1. 二等座(O) 2. 一等座(M) 3. 商务座(9) 4. 硬卧(3) 5. 硬座(4) 6. 软卧(4)
            log.info("开始订单状况检测");
            requestEntity.setUrl("https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo");
            requestEntity.addParam("REPEAT_SUBMIT_TOKEN", globalRepeatSubmitToken);
            requestEntity.addParam("_json_att", "");
            requestEntity.addParam("bed_level_order_num", "000000000000000000000000000000");
            requestEntity.addParam("cancel_flag", "2");
            String oldPassengerStr = getOldPassengerStr(user.getName(), user.getIdType(), user.getId(), user.getTicketType());
            requestEntity.addParam("oldPassengerStr", oldPassengerStr);
            String passengerTicketStr = getPassengerTicketStr(seatType, user.getTicketType(), user.getName(), user.getIdType(), user.getId(), user.getPhone());
            requestEntity.addParam("passengerTicketStr", passengerTicketStr);
            requestEntity.addParam("randCode", "");
            requestEntity.addParam("tour_flag", "dc");
            requestEntity.addParam("whatsSelect", "1");
            responseEntity = HttpClientUtils.doRequest(requestEntity);
            System.out.println(responseEntity);
            JSONObject checkOrderJSON = JSONObject.parseObject(responseEntity.getResult());
            if (!checkOrderJSON.getBoolean("status")) {
                log.info("订单检测失败，status返回false");
                return false;
            } else {
                if (!checkOrderJSON.getJSONObject("data").getBoolean("submitStatus")) {
                    log.info("订单检测失败，status返回false");
                    return false;
                }
            }
            //ResponseEntity(httpCode=200, message=请求成功, result={"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"ifShowPassCode":"N","canChooseBeds":"N","canChooseSeats":"Y","choose_Seats":"O9M","isCanChooseMid":"N","ifShowPassCodeTime":"3099","submitStatus":true,"smokeStr":""},"messages":[],"validateMessages":{}})
            log.info("订单状况检测通过，开始锁定座位");
            requestEntity.setUrl("https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount");
            requestEntity.clearParams();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            requestEntity.addParam("train_date", (simpleDateFormat.parse(ticketData.getDate())).toString());
            requestEntity.addParam("train_no", ticketData.getTicketDetail().getTrainNo());
            requestEntity.addParam("stationTrainCode", ticketData.getTicketDetail().getStationTrainCode());
            requestEntity.addParam("seatType", seatType);
            requestEntity.addParam("fromStationTelecode", ticketData.getTicketDetail().getFromStationTeleCode());
            requestEntity.addParam("toStationTelecode", ticketData.getTicketDetail().getToStationTeleCode());
            requestEntity.addParam("leftTicket", ticketData.getTicketDetail().getYpInfo());
            requestEntity.addParam("purpose_codes", "00");
            requestEntity.addParam("train_location", ticketData.getTicketDetail().getLocationCode());
            requestEntity.addParam("_json_att", "");
            requestEntity.addParam("REPEAT_SUBMIT_TOKEN", globalRepeatSubmitToken);
            responseEntity = HttpClientUtils.doRequest(requestEntity);
            System.out.println(responseEntity);
            JSONObject queueJSON = JSONObject.parseObject(responseEntity.getResult());
            if (!queueJSON.getBoolean("status")) {
                //请求失败返回
                log.info("锁定车位失败，status返回false");
                return false;
            } else {
                if (queueJSON.getJSONObject("data").getBoolean("op_2")) {
                    log.info("锁定车位失败，排队人数过多");
                    return false;
                } else {
                    String ticketNums = queueJSON.getJSONObject("data").getString("ticket");
                    ticketNums = ticketNums.split(",")[0];
                    if (Integer.parseInt(ticketNums) <= 0) {
                        log.info("锁定车位失败，余票不足");
                        return false;
                    }
                }
            }
            //result={"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"count":"0","ticket":"139,0","op_2":"false","countT":"0","op_1":"false"},"messages":[],"validateMessages":{}})

            log.info("锁定座位成功，开始提交订单");
            requestEntity.setUrl("https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue");
            requestEntity.clearParams();
            requestEntity.addParam("REPEAT_SUBMIT_TOKEN", globalRepeatSubmitToken);
            requestEntity.addParam("_json_att", "");
            requestEntity.addParam("choose_seats", "");
            requestEntity.addParam("dwAll", "N");
            requestEntity.addParam("key_check_isChange", key_check_isChange);
            requestEntity.addParam("leftTicketStr", ticketData.getTicketDetail().getYpInfo());
            requestEntity.addParam("oldPassengerStr", oldPassengerStr);
            requestEntity.addParam("passengerTicketStr", passengerTicketStr);
            requestEntity.addParam("purpose_codes", "00");
            requestEntity.addParam("randCode", "");
            requestEntity.addParam("roomType", "00");
            requestEntity.addParam("seatDetailType", "000");
            requestEntity.addParam("train_location", ticketData.getTicketDetail().getLocationCode());
            requestEntity.addParam("whatsSelect", "1");
            responseEntity = HttpClientUtils.doRequest(requestEntity);
            System.out.println(responseEntity);
            JSONObject submitJSON = JSONObject.parseObject(responseEntity.getResult());
            if (!submitJSON.getBoolean("status")) {
                log.info("购票确认失败，status返回false");
                return false;
            } else if (!submitJSON.getJSONObject("data").getBoolean("submitStatus")) {
                log.info("购票确认失败，submitStatus返回false");
                return false;
            }
            //{"validateMessagesShowId":"_validatorMessage","status":true,"httpstatus":200,"data":{"submitStatus":true},"messages":[],"validateMessages":{}}
            return true;
        } catch (Exception e) {
            System.out.println("发生异常");
            return false;
        }
    }

    private String getPassengerTicketStr(String seatType, String ticketType, String name, String idType, String id, String phone) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(seatType);
        stringBuilder.append(",0,");
        stringBuilder.append(ticketType);
        stringBuilder.append(",");
        stringBuilder.append(name);
        stringBuilder.append(",");
        stringBuilder.append(idType);
        stringBuilder.append(",");
        stringBuilder.append(id);
        stringBuilder.append(",");
        stringBuilder.append(phone);
        stringBuilder.append(",N");
        return stringBuilder.toString();
    }

    private String getOldPassengerStr(String name, String idType, String id, String ticketType) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(name);
        stringBuilder.append(",");
        stringBuilder.append(idType);
        stringBuilder.append(",");
        stringBuilder.append(id);
        stringBuilder.append(",");
        stringBuilder.append(ticketType);
        stringBuilder.append(",_");
        return stringBuilder.toString();
    }

    private String buildStringBody(TicketData ticketData) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("secretStr=");
        stringBuilder.append(ticketData.getSecretStr());
        stringBuilder.append("&train_date=");
        stringBuilder.append(ticketData.getDate());
        stringBuilder.append("&back_train_date=");
        stringBuilder.append(ticketData.getDate());
        stringBuilder.append("&tour_flag=dc");
        stringBuilder.append("&purpose_codes=ADULT");
        stringBuilder.append("&query_from_station_name=");
        stringBuilder.append(ticketData.getTicketDetail().getFromStationName());
        stringBuilder.append("&query_to_station_name=");
        stringBuilder.append(ticketData.getTicketDetail().getToStationName());
        stringBuilder.append("&undefined");
        return stringBuilder.toString();
    }

    private String checkSeatType(List<String> orderSeatType, TicketDetail ticketDetail) {
        if (ticketDetail.getCanWebBuy().equals("N")) {
            return null;
        } else {
            for (String seatType : orderSeatType) {
                SeatTypeContents instance = SeatTypeContents.getInstance(seatType);
                if (instance == null) {
                    System.out.println("不支持的类型" + seatType);
                    continue;
                }
                switch (instance) {
                    case 硬座:
                        return coverTicketNum(ticketDetail.getYzNum(), null) > 0 ? seatType : null;
                    case 软座:
                        return coverTicketNum(ticketDetail.getRzNum(), null) > 0 ? seatType : null;
                    case 硬卧:
                        return coverTicketNum(ticketDetail.getYwNum(), null) > 0 ? seatType : null;
                    case 软卧:
                        return coverTicketNum(ticketDetail.getRwNum(), null) > 0 ? seatType : null;
                    case 高级软卧:
                        return coverTicketNum(ticketDetail.getGrNum(), null) > 0 ? seatType : null;
                    case 一等座:
                        return coverTicketNum(ticketDetail.getZyNum(), null) > 0 ? seatType : null;
                    case 二等座:
                        return coverTicketNum(ticketDetail.getZeNum(), null) > 0 ? seatType : null;
                    case 商务座_特等座:
                        return coverTicketNum(ticketDetail.getSwzNum(), ticketDetail.getTzNum()) > 0 ? seatType : null;
                    default:
                        return null;
                }
            }
        }
        return null;
    }

    private int coverTicketNum(String ticketNum1, String ticketNum2) {
        String ticketNum;
        if (StringUtils.isEmpty(ticketNum1) && StringUtils.isEmpty(ticketNum2)) {
            return 0;
        } else {
            if (StringUtils.isEmpty(ticketNum1)) {
                ticketNum = ticketNum2;
            } else {
                ticketNum = ticketNum1;
            }
        }
        try {
            if (ticketNum.equals("有")) {
                return 99;
            }
            return Integer.parseInt(ticketNum);
        } catch (Exception e) {
            return 0;
        }
    }
}
